cssnode: Add visibility concept
authorBenjamin Otte <otte@redhat.com>
Tue, 10 Feb 2015 01:50:57 +0000 (02:50 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 18 Mar 2015 14:23:31 +0000 (15:23 +0100)
This allows hiding nodes of invisible widgets.
And that in turn makes sure :nth-child() works as expected.

gtk/gtkcssmatcher.c
gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h
gtk/gtkcsswidgetnode.c
gtk/gtkwidget.c

index 956271a78ead30b7846667ed4b1abdfe49594f8d..b2b5c75a53d64f55ee282c35e20baaf5bc3b1aa1 100644 (file)
@@ -256,13 +256,33 @@ gtk_css_matcher_node_get_parent (GtkCssMatcher       *matcher,
   return gtk_css_node_init_matcher (node, matcher);
 }
 
+static GtkCssNode *
+get_previous_visible_sibling (GtkCssNode *node)
+{
+  do {
+    node = gtk_css_node_get_previous_sibling (node);
+  } while (node && !gtk_css_node_get_visible (node));
+
+  return node;
+}
+
+static GtkCssNode *
+get_next_visible_sibling (GtkCssNode *node)
+{
+  do {
+    node = gtk_css_node_get_next_sibling (node);
+  } while (node && !gtk_css_node_get_visible (node));
+
+  return node;
+}
+
 static gboolean
 gtk_css_matcher_node_get_previous (GtkCssMatcher       *matcher,
                                    const GtkCssMatcher *next)
 {
   GtkCssNode *node;
   
-  node = gtk_css_node_get_previous_sibling (next->node.node);
+  node = get_previous_visible_sibling (next->node.node);
   if (node == NULL)
     return FALSE;
 
@@ -340,7 +360,7 @@ gtk_css_matcher_node_nth_child (GtkCssNode *node,
       if (node == NULL)
         return FALSE;
 
-      node = gtk_css_node_get_previous_sibling (node);
+      node = get_previous_visible_sibling (node);
     }
 
   if (a == 0)
@@ -352,7 +372,7 @@ gtk_css_matcher_node_nth_child (GtkCssNode *node,
   while (node)
     {
       b++;
-      node = gtk_css_node_get_previous_sibling (node);
+      node = get_previous_visible_sibling (node);
     }
 
   return b % a == 0;
@@ -368,7 +388,7 @@ gtk_css_matcher_node_nth_last_child (GtkCssNode *node,
       if (node == NULL)
         return FALSE;
 
-      node = gtk_css_node_get_next_sibling (node);
+      node = get_next_visible_sibling (node);
     }
 
   if (a == 0)
@@ -380,7 +400,7 @@ gtk_css_matcher_node_nth_last_child (GtkCssNode *node,
   while (node)
     {
       b++;
-      node = gtk_css_node_get_next_sibling (node);
+      node = get_next_visible_sibling (node);
     }
 
   return b % a == 0;
index 402aa3366df0e65394d1bed5e324dc8bc2a542a9..5040ff23b1098298d0c6ec87a2b0d6d222b212e0 100644 (file)
@@ -44,7 +44,7 @@ gtk_css_node_set_invalid (GtkCssNode *node,
 
   if (node->parent)
     {
-      if (invalid)
+      if (invalid && node->visible)
         gtk_css_node_set_invalid (node->parent, TRUE);
     }
   else
@@ -343,6 +343,8 @@ gtk_css_node_init (GtkCssNode *cssnode)
   cssnode->decl = gtk_css_node_declaration_new ();
 
   cssnode->style = g_object_ref (gtk_css_static_style_get_default ());
+
+  cssnode->visible = TRUE;
 }
 
 static void
@@ -436,17 +438,19 @@ gtk_css_node_reposition (GtkCssNode *node,
       else
         {
           g_object_unref (node);
-          gtk_css_node_set_children_changed (node->parent);
+          if (node->visible)
+            gtk_css_node_set_children_changed (node->parent);
         }
 
       node->parent = parent;
 
       if (parent)
         {
-          gtk_css_node_set_children_changed (parent);
+          if (node->visible)
+            gtk_css_node_set_children_changed (parent);
           g_object_ref (node);
 
-          if (node->invalid)
+          if (node->invalid && node->visible)
             gtk_css_node_set_invalid (parent, TRUE);
         }
       else
@@ -564,6 +568,25 @@ gtk_css_node_get_style (GtkCssNode *cssnode)
   return cssnode->style;
 }
 
+void
+gtk_css_node_set_visible (GtkCssNode *cssnode,
+                          gboolean    visible)
+{
+  if (cssnode->visible == visible)
+    return;
+
+  cssnode->visible = visible;
+
+  if (cssnode->parent)
+    gtk_css_node_set_children_changed (cssnode->parent);
+}
+
+gboolean
+gtk_css_node_get_visible (GtkCssNode *cssnode)
+{
+  return cssnode->visible;
+}
+
 void
 gtk_css_node_set_widget_type (GtkCssNode *cssnode,
                               GType       widget_type)
@@ -761,7 +784,8 @@ gtk_css_node_validate (GtkCssNode            *cssnode,
        child;
        child = gtk_css_node_get_next_sibling (child))
     {
-      gtk_css_node_validate (child, timestamp, changes);
+      if (child->visible)
+        gtk_css_node_validate (child, timestamp, changes);
     }
 
   _gtk_bitmask_free (changes);
index 3c6abfdb23687b7037fca2245db47cb46eb94f7b..ea082ba9ad90eeebfab6b12f93c3ac5cc242ea4e 100644 (file)
@@ -49,6 +49,7 @@ struct _GtkCssNode
 
   GtkCssChange           pending_changes;       /* changes that accumulated since the style was last computed */
 
+  guint                  visible :1;            /* node will be skipped when validating or computing styles */
   guint                  invalid :1;            /* node or a child needs to be validated (even if just for animation) */
   guint                  children_changed :1;   /* the children changed since last validation */
 };
@@ -88,6 +89,10 @@ GtkCssNode *            gtk_css_node_get_last_child     (GtkCssNode            *
 GtkCssNode *            gtk_css_node_get_previous_sibling(GtkCssNode           *cssnode);
 GtkCssNode *            gtk_css_node_get_next_sibling   (GtkCssNode            *cssnode);
 
+void                    gtk_css_node_set_visible        (GtkCssNode            *cssnode,
+                                                         gboolean               visible);
+gboolean                gtk_css_node_get_visible        (GtkCssNode            *cssnode);
+
 void                    gtk_css_node_set_widget_type    (GtkCssNode            *cssnode,
                                                          GType                  widget_type);
 GType                   gtk_css_node_get_widget_type    (GtkCssNode            *cssnode);
index 5c89a9812478493b1c27a0e585f88caf2fab1aab..d142c93e105b0173256d961874093422255bf7be 100644 (file)
@@ -294,6 +294,8 @@ gtk_css_widget_node_new (GtkWidget *widget)
 
   result = g_object_new (GTK_TYPE_CSS_WIDGET_NODE, NULL);
   result->widget = widget;
+  gtk_css_node_set_visible (GTK_CSS_NODE (result),
+                            gtk_widget_get_visible (widget));
 
   return GTK_CSS_NODE (result);
 }
index e13145ccfee30e0bfc1e34cbf52d0c1bd8767290..cfb4223bfa03703af10a3cadabe01d19840bc7cd 100644 (file)
@@ -4869,6 +4869,8 @@ gtk_widget_show (GtkWidget *widget)
             gtk_widget_queue_compute_expand (widget->priv->parent);
         }
 
+      gtk_css_node_set_visible (widget->priv->cssnode, TRUE);
+
       g_signal_emit (widget, widget_signals[SHOW], 0);
       g_object_notify (G_OBJECT (widget), "visible");
 
@@ -4967,6 +4969,8 @@ gtk_widget_hide (GtkWidget *widget)
           gtk_widget_queue_compute_expand (widget);
         }
 
+      gtk_css_node_set_visible (widget->priv->cssnode, FALSE);
+
       g_signal_emit (widget, widget_signals[HIDE], 0);
       if (!gtk_widget_is_toplevel (widget))
        gtk_widget_queue_resize (widget);